//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008-2010, Shane J. M. Liesegang
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright 
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in the 
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the copyright holder nor the names of any 
//       contributors may be used to endorse or promote products derived from 
//       this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//////////////////////////////////////////////////////////////////////////////

#include "Common.h"
#include "Controller.h"

#include "InputManager.h"
#include "MathUtil.h"



 // Here are the definitions from XInput.h
#ifndef XINPUT_GAMEPAD_DPAD_UP
        #define XINPUT_GAMEPAD_DPAD_UP          0x00000001
        #define XINPUT_GAMEPAD_DPAD_DOWN        0x00000002
        #define XINPUT_GAMEPAD_DPAD_LEFT        0x00000004
        #define XINPUT_GAMEPAD_DPAD_RIGHT       0x00000008
        #define XINPUT_GAMEPAD_START            0x00000010
        #define XINPUT_GAMEPAD_BACK             0x00000020
        #define XINPUT_GAMEPAD_LEFT_THUMB       0x00000040
        #define XINPUT_GAMEPAD_RIGHT_THUMB      0x00000080
        #define XINPUT_GAMEPAD_LEFT_SHOULDER    0x0100
        #define XINPUT_GAMEPAD_RIGHT_SHOULDER   0x0200
        #define XINPUT_GAMEPAD_A                0x1000
        #define XINPUT_GAMEPAD_B                0x2000
        #define XINPUT_GAMEPAD_X                0x4000
        #define XINPUT_GAMEPAD_Y                0x8000
        #define XINPUT_GAMEPAD_TRIGGER_THRESHOLD        30
        #define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE      7849
        #define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#endif


/*
 // The definitions sussed out from the Apple HID Utilities 
 Generic Desktop X - Left X                     - 0x1b
 Generic Dekstop Y - Left Y                     - 0x1c
 Generic Desktop Rx - Right X           - 0x1d
 Generic Desktop Ry - Right Y           - 0x1e
 Button #0x000C - Dpad Up                       - 0x0a
 Button #0x000D - Dpad Down                     - 0x0b
 Button #0x000E - Dpad Left                     - 0x0c
 Button #0x000F - Dpad Right            - 0x0d
 Button #0x0009 - Start                         - 0x0e
 Button #0x000A - Back                          - 0x0f
 Button #0x0007 - L3                            - 0x10
 Button #0x0008 - R3                            - 0x11
 Button #0x0005 - Left Bumper           - 0x12
 Button #0x0006 - Right Bumper          - 0x13
 Button #0x000B - Xbox Button           - 0x14
 Button #0x0001 - A Button                      - 0x15
 Button #0x0002 - B Button                      - 0x16
 Button #0x0003 - X Button                      - 0x17
 Button #0x0004 - Y Button                      - 0x18
 Generic Desktop Z - Left Trigger       - 0x19
 Generic Desktop Rz - Right Trigger - 0x1a
*/


ControllerManager* ControllerManager::s_ControllerManager = NULL;

ControllerManager& ControllerManager::GetInstance()
{
        if (s_ControllerManager == NULL)
        {
                s_ControllerManager = new ControllerManager();
        }
        return *s_ControllerManager;
}

ControllerManager::ControllerManager()
{       
        _controllers[0] = new Controller();
        _controllers[0]->_controllerID = 0;
        
        _controllers[1] = new Controller();
        _controllers[1]->_controllerID = 1;
}

ControllerManager::~ControllerManager()
{
        #if defined(__APPLE__)
                HIDReleaseAllDeviceQueues();
                HIDReleaseDeviceList();
        #endif
}

void ControllerManager::Setup()
{
        _controllers[0]->Setup();
        _controllers[1]->Setup();
}

void ControllerManager::UpdateState()
{       
        _controllers[0]->UpdateState();
        _controllers[1]->UpdateState();
}

Controller* Controller::s_Controller = NULL;

Controller::Controller()
{
        _connected = false;
        _currentLeftVibration = 0;
        _currentRightVibration = 0;
        
        #if defined(__APPLE__)
                _device = NULL;
        #endif
}

void Controller::Setup()
{
        #if defined(WIN32)
                ZeroMemory( &_currentControllerRawState, sizeof(XINPUT_STATE));
                
                _dwResult = XInputGetState(0, &_currentControllerRawState);
                
                if (_dwResult == ERROR_SUCCESS)
                {
                        sysLog.Printf("Controller %d connected!", _controllerID+1);
                        _connected = true;
                }
                else
                {
                        sysLog.Printf("Controller %d not present...", _controllerID+1);
                        ZeroMemory( &_currentControllerRawState, sizeof(XINPUT_STATE));
                        _connected = false;
                }
        
        #elif defined(__APPLE__)
                unsigned long usagePage = 0;
                unsigned long usage = 0;
                if (!HIDHaveDeviceList())
                {       
                        HIDBuildDeviceList(usagePage, usage);
                }
                
                _device = HIDGetFirstDevice();
                while (_device != NULL)
                {
                        //is this device already taken by another controller? 
                        bool breakIt = false;
                        for (int i=0; i < MAX_CONTROLLERS; i++)
                        {
                                Controller* check = &theControllerManager.GetController(i);
                                if ((check != this) && (check->_device == _device))
                                {
                                        _device = HIDGetNextDevice(_device);
                                        if (_device == NULL)
                                        {
                                                breakIt = true;
                                        }
                                }
                        }
                        if (breakIt)
                        {
                                break;
                        }
                        
                        std::string manufacturer = _device->manufacturer;
                        std::string product = _device->product;
                        if (manufacturer.length() > 0)
                                manufacturer = manufacturer.substr(1, manufacturer.length()-1).c_str(); //trimming off the initial copyright symbol so matching won't be dumb
                        if ((manufacturer == "Microsoft Corporation") && (product == "Controller"))
                        {
                                sysLog.Printf("Controller %d connected!", _controllerID+1);
                                _connected = true;
                                break;
                        }
                        
                        _device = HIDGetNextDevice(_device);
                }
                if (_device == NULL)
                {
                        sysLog.Printf("Controller %d not present...", _controllerID+1);
                        _connected = false;
                }
                else
                {
                        pRecElement current_element = HIDGetFirstDeviceElement(_device, kHIDElementTypeIO);
                        while (current_element != NULL)
                        {
                                _elements[(unsigned int)current_element->cookie] = current_element;
                                current_element = HIDGetNextDeviceElement(current_element, kHIDElementTypeIO);
                        }
                }
        #elif defined(__linux__)
                char* devicePath;
                if (_controllerID == 0)
                        devicePath = LINUX_CONTROLLER_1_PATH;
                else
                        devicePath = LINUX_CONTROLLER_2_PATH;

                _deviceFD = open(devicePath, O_RDONLY | O_NONBLOCK);
                if (_deviceFD < 0)
                {
                        sysLog.Printf("Controller %d not present...", _controllerID+1);
                        _connected = false;
                }
                else
                {
                        sysLog.Printf("Controller %d connected!", _controllerID+1);
                        _connected = true;
                }

                // Discover the force feedback device.
                bool foundFirstController = false;
                _ffFD = -1;
                for (int i = 0; i < MAX_LINUX_EVENT_INTERFACES; i++)
                {
                        std::stringstream ss;
                        ss << i;
                        String eventDev = LINUX_EVENT_INTERFACE + ss.str();
                        int fd = open(eventDev.c_str(), O_RDWR);
                        if (fd >= 0)
                        {
                                char name[256] = "Unknown";
                                ioctl(fd, EVIOCGNAME(sizeof(name)), name);
                                if (strcmp(name, "Microsoft X-Box 360 pad") == 0)
                                {
                                        if (_controllerID == 0)
                                        {
                                                _ffFD = fd;
                                                break;
                                        }
                                        else
                                        {
                                                if (foundFirstController)
                                                {
                                                        _ffFD = fd;
                                                        break;
                                                }
                                                else
                                                {
                                                        foundFirstController = true;
                                                        close(fd);
                                                }
                                        }
                                }
                                else
                                {
                                        close(fd);
                                }
                        }
                }
                if (_ffFD < 0)
                {
                        sysLog.Printf("Error opening Force Feedback device for controller %d!", _controllerID+1);
                }
                else
                {
                        _ffEffect.type = FF_RUMBLE;
                        _ffEffect.id = -1;
                        _ffEffect.u.rumble.strong_magnitude = 0;
                        _ffEffect.u.rumble.weak_magnitude = 0;
                        _ffEffect.replay.length = 0x7fff;
                        _ffEffect.replay.delay = 0;
                        _ffPlay.type = EV_FF;
                        _ffPlay.value = 1;
                }
        #endif
}

void Controller::UpdateState()
{
        if(!_connected)
        {
                return;
        }
        #if defined(WIN32)
                _dwResult = XInputGetState(_controllerID, &_currentControllerRawState);
                
                // We either don't have a controller or the Input has failed.  Keep clearing the input
                // data so we don't get garbage input.
                if (_dwResult != ERROR_SUCCESS)
                {
                        if (_connected)
                        {
                                sysLog.Printf("Uh oh, we lost controller %d...", _controllerID+1);
                        }
                        
                        _connected = false;
                        ZeroMemory( &_currentControllerRawState, sizeof(XINPUT_STATE));
                        _currentControllerInput.LeftThumbstickX = 
                        _currentControllerInput.LeftThumbstickY =
                        _currentControllerInput.RightThumbstickX =
                        _currentControllerInput.RightThumbstickY = 
                        _currentControllerInput.LeftTriggerValue = 
                        _currentControllerInput.RightTriggerValue = 
                        _currentControllerInput.Buttons = 0;
                        return;
                }
                
                _connected = true;
                
                _currentControllerInput.Buttons = _currentControllerRawState.Gamepad.wButtons;
                //TODO: dpad
                _currentControllerInput.LeftTriggerValue = (int)_currentControllerRawState.Gamepad.bLeftTrigger;
                _currentControllerInput.RightTriggerValue = (int)_currentControllerRawState.Gamepad.bRightTrigger;
                _currentControllerInput.LeftThumbstickX = _currentControllerRawState.Gamepad.sThumbLX;
                _currentControllerInput.LeftThumbstickY = _currentControllerRawState.Gamepad.sThumbLY;
                _currentControllerInput.RightThumbstickX = _currentControllerRawState.Gamepad.sThumbRX;
                _currentControllerInput.RightThumbstickY = _currentControllerRawState.Gamepad.sThumbRY;
                
        #elif defined(__APPLE__)
                _currentControllerInput.LeftThumbstickX = _getValueForCookie(0x1b);
                _currentControllerInput.LeftThumbstickY = -_getValueForCookie(0x1c);
                _currentControllerInput.RightThumbstickX = _getValueForCookie(0x1d);
                _currentControllerInput.RightThumbstickY = -_getValueForCookie(0x1e);
                _currentControllerInput.LeftTriggerValue = _getValueForCookie(0x19);
                _currentControllerInput.RightTriggerValue = _getValueForCookie(0x1a);
                
                _currentControllerInput.Buttons = 0;
                if (_getValueForCookie(0x0a))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_DPAD_UP;
                if (_getValueForCookie(0x0b))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_DPAD_DOWN;
                if (_getValueForCookie(0x0c))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_DPAD_LEFT;
                if (_getValueForCookie(0x0d))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_DPAD_RIGHT;
                if (_getValueForCookie(0x0e))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_START;
                if (_getValueForCookie(0x0f))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_BACK;
                if (_getValueForCookie(0x10))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_LEFT_THUMB;
                if (_getValueForCookie(0x11))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_RIGHT_THUMB;
                if (_getValueForCookie(0x12))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_LEFT_SHOULDER;
                if (_getValueForCookie(0x13))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_RIGHT_SHOULDER;
                if (_getValueForCookie(0x15))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_A;
                if (_getValueForCookie(0x16))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_B;
                if (_getValueForCookie(0x17))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_X;
                if (_getValueForCookie(0x18))
                        _currentControllerInput.Buttons |= XINPUT_GAMEPAD_Y;

        #elif defined(__linux__)
                struct js_event js;
                while (read(_deviceFD, &js, sizeof(struct js_event)) == sizeof(struct js_event))
                {
                        switch (js.type)
                        {
                                case JS_EVENT_BUTTON:
                                        unsigned int currButton;
                                        switch (js.number)
                                        {
                                                case 0:
                                                        currButton = XINPUT_GAMEPAD_A;
                                                        break;
                                                case 1:
                                                        currButton = XINPUT_GAMEPAD_B;
                                                        break;
                                                case 2:
                                                        currButton = XINPUT_GAMEPAD_X;
                                                        break;
                                                case 3:
                                                        currButton = XINPUT_GAMEPAD_Y;
                                                        break;
                                                case 4:
                                                        currButton = XINPUT_GAMEPAD_LEFT_SHOULDER;
                                                        break;
                                                case 5:
                                                        currButton = XINPUT_GAMEPAD_RIGHT_SHOULDER;
                                                        break;
                                                case 6:
                                                        currButton = XINPUT_GAMEPAD_START;
                                                        break;
                                                case 7:
                                                        // Big 'X' button - not used.
                                                        continue;
                                                case 8:
                                                        currButton = XINPUT_GAMEPAD_LEFT_THUMB;
                                                        break;
                                                case 9:
                                                        currButton = XINPUT_GAMEPAD_RIGHT_THUMB;
                                                        break;
                                                case 10:
                                                        currButton = XINPUT_GAMEPAD_BACK;
                                                        break;
                                                default:
                                                        sysLog.Printf("Error! Unknown button press event received!\n");
                                                        continue;
                                        }
                                        if (js.value) // button pressed
                                                _currentControllerInput.Buttons |= currButton;
                                        else // button released
                                                _currentControllerInput.Buttons &= ~currButton;
                                        break;
                                        case JS_EVENT_AXIS:
                                        switch (js.number)
                                        {
                                                case 0:
                                                        _currentControllerInput.LeftThumbstickX = js.value;
                                                        break;
                                                case 1:
                                                        _currentControllerInput.LeftThumbstickY = -js.value;
                                                        break;
                                                case 2:
                                                        _currentControllerInput.LeftTriggerValue = js.value;
                                                        break;
                                                case 3:
                                                        _currentControllerInput.RightThumbstickX = js.value;
                                                        break;
                                                case 4:
                                                        _currentControllerInput.RightThumbstickY = -js.value;
                                                        break;
                                                case 5:
                                                        _currentControllerInput.RightTriggerValue = js.value;
                                                        break;
                                                case 6:
                                                        if (js.value == 0)
                                                                _currentControllerInput.Buttons &= ~(XINPUT_GAMEPAD_DPAD_LEFT & XINPUT_GAMEPAD_DPAD_RIGHT);
                                                        else if (js.value < 0)
                                                                _currentControllerInput.Buttons |= XINPUT_GAMEPAD_DPAD_LEFT;
                                                        else
                                                                _currentControllerInput.Buttons |= XINPUT_GAMEPAD_DPAD_RIGHT;
                                                        break;
                                                case 7:
                                                        if (js.value == 0)
                                                                _currentControllerInput.Buttons &= ~(XINPUT_GAMEPAD_DPAD_UP & XINPUT_GAMEPAD_DPAD_DOWN);
                                                        else if (js.value < 0)
                                                                _currentControllerInput.Buttons |= XINPUT_GAMEPAD_DPAD_UP;
                                                        else
                                                                _currentControllerInput.Buttons |= XINPUT_GAMEPAD_DPAD_DOWN;
                                                        break;
                                                default:
                                                        sysLog.Printf("Error! Unknown axis event received!\n");
                                                        break;
                                        }
                                        break;
                                        default:
                                        break;
                        }
                }
        #endif
        
        //Using the built-in deadzone -- comment out if you don't like it
        if (_currentControllerInput.LeftThumbstickX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
                _currentControllerInput.LeftThumbstickX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
                _currentControllerInput.LeftThumbstickY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE &&
                _currentControllerInput.LeftThumbstickY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
        {
                _currentControllerInput.LeftThumbstickX = 0;
                _currentControllerInput.LeftThumbstickY = 0;
        }
        if (_currentControllerInput.RightThumbstickX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE &&
                _currentControllerInput.RightThumbstickX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE &&
                _currentControllerInput.RightThumbstickY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE &&
                _currentControllerInput.RightThumbstickY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
        {
                _currentControllerInput.RightThumbstickX = 0;
                _currentControllerInput.RightThumbstickY = 0;
        }
        
        theInput.HandleControl( *this );
}

const ControllerInput Controller::GetState()
{
        return _currentControllerInput;
}

const Vector2 Controller::GetLeftThumbVec2()
{
        Vector2 forReturn;
        forReturn.X = float(_currentControllerInput.LeftThumbstickX) / 32768.0f;
        forReturn.Y = float(_currentControllerInput.LeftThumbstickY) / 32768.0f;
        return forReturn;
}

const Vector2 Controller::GetRightThumbVec2()
{
        Vector2 forReturn;
        forReturn.X = float(_currentControllerInput.RightThumbstickX) / 32768.0f;
        forReturn.Y = float(_currentControllerInput.RightThumbstickY) / 32768.0f;
        return forReturn;
}

const Vec2i Controller::GetLeftThumbstick()
{
        Vec2i forReturn;
        forReturn.X = _currentControllerInput.LeftThumbstickX;
        forReturn.Y = _currentControllerInput.LeftThumbstickY;
        return forReturn;
}
const Vec2i Controller::GetRightThumbstick()
{
        Vec2i forReturn;
        forReturn.X = _currentControllerInput.RightThumbstickX;
        forReturn.Y = _currentControllerInput.RightThumbstickY;
        return forReturn;
}

const int Controller::GetRightTrigger()
{
        return _currentControllerInput.RightTriggerValue;
}

const int Controller::GetLeftTrigger()
{
        return _currentControllerInput.LeftTriggerValue;
}

const bool Controller::IsButtonDown(int buttonMask)
{
        return ((_currentControllerInput.Buttons & buttonMask) != 0);
}

const bool Controller::IsAButtonDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_A)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsBButtonDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_B)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsXButtonDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_X)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsYButtonDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_Y)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsLeftThumbstickButtonDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_LEFT_THUMB)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsRightThumbstickButtonDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_RIGHT_THUMB)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsStartButtonDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_START)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsBackButtonDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_BACK)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsLeftBumperDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_LEFT_SHOULDER)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsRightBumperDown()
{
        if(_currentControllerInput.Buttons & XINPUT_GAMEPAD_RIGHT_SHOULDER)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsLeftTriggerPressed()
{
        if (_currentControllerInput.LeftTriggerValue > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
        {
                return true;
        }
        else
        {
                return false;
        }
}

const bool Controller::IsRightTriggerPressed()
{
        if (_currentControllerInput.RightTriggerValue > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
        {
                return true;
        }
        else
        {
                return false;
        }
}


const unsigned int Controller::GetLeftVibration()
{
        return _currentLeftVibration;
}

const unsigned int Controller::GetRightVibration()
{
        return _currentRightVibration;
}

void Controller::SetLeftVibrationRaw(unsigned int newVibration)
{
#if defined(WIN32)
        XINPUT_VIBRATION vibration;
        ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION));
        vibration.wLeftMotorSpeed = _currentLeftVibration = newVibration;
        vibration.wRightMotorSpeed = _currentRightVibration;
        XInputSetState(0, &vibration);
#elif defined(__APPLE__)
        newVibration = 0;
#elif defined(__linux__)
        _ffEffect.u.rumble.strong_magnitude = _currentLeftVibration = newVibration;
        _ffEffect.u.rumble.weak_magnitude = _currentRightVibration;
        if (ioctl(_ffFD, EVIOCSFF, &_ffEffect) == -1)
        {
                sysLog.Printf("Error writing force feedback effect!");
                return;
        }
        _ffPlay.code = _ffEffect.id;
        if (write(_ffFD, &_ffPlay, sizeof(_ffPlay)) == -1)
        {
                sysLog.Printf("Error playing force feedback effect!");
        }
#endif
}

void Controller::SetRightVibrationRaw(unsigned int newVibration)
{
#if defined(WIN32)
        XINPUT_VIBRATION vibration;
        ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION));
        vibration.wLeftMotorSpeed = _currentLeftVibration;
        vibration.wRightMotorSpeed = _currentRightVibration = newVibration;
        XInputSetState(0, &vibration);
#elif defined(__APPLE__)
        newVibration = 0;
#elif defined(__linux__)
        _ffEffect.u.rumble.strong_magnitude = _currentLeftVibration;
        _ffEffect.u.rumble.weak_magnitude = _currentRightVibration = newVibration;
        if (ioctl(_ffFD, EVIOCSFF, &_ffEffect) == -1)
        {
                sysLog.Printf("Error writing force feedback effect!");
                return;
        }
        _ffPlay.code = _ffEffect.id;
        if (write(_ffFD, &_ffPlay, sizeof(_ffPlay)) == -1)
        {
                sysLog.Printf("Error playing force feedback effect!");
        }
#endif
}

void Controller::SetLeftVibration(unsigned int newVibration)
{
        newVibration = MathUtil::Clamp(newVibration, 0, 255);
        if (newVibration == 255)
        {
                SetLeftVibrationRaw(65535);
        }
        else
        {
                SetLeftVibrationRaw(newVibration << 8);
        }
}

void Controller::SetRightVibration(unsigned int newVibration)
{
        newVibration = MathUtil::Clamp(newVibration, 0, 255);
        if (newVibration == 255)
        {
                SetRightVibrationRaw(65535);
        }
        else
        {
                SetRightVibrationRaw(newVibration << 8);
        }
}